package com.youdianstar.app.common.util;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Locale;

/**
 * File: MathUtil
 * Author: 82149 Create: 2019/12/13 10:35
 * Changes (from 2019/12/13)
 * --------------------------------------------------
 * describe:
 * ---------------------------------------------------
 */
public class MathUtil {
    // 默认除法运算精度
    private static final int DEF_DIV_SCALE = 10;

    private static final int COMMONSCALE = 2;

    /**
     * 提供精确的加法运算。
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */

    public static float add(float v1, float v2) {
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.add(b2).floatValue();
    }

    /**
     * 提供精确的加法运算。
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */

    public static double add(double v1, double v2, boolean isRound) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        if (isRound)
            return round(b1.add(b2)).doubleValue();
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */

    public static float sub(float v1, float v2) {
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.subtract(b2).floatValue();
    }


    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */

    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static float mul(float v1, float v2) {
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.multiply(b2).floatValue();
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后10位，以后的数字四舍五入。
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static float div(float v1, float v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */

    public static float div(float v1, float v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */

    public static float div(int v1, int v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b1 = new BigDecimal(Float.toString(v1));
        BigDecimal b2 = new BigDecimal(Float.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static float round(float v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b = new BigDecimal(Float.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).floatValue();
    }


    public static String round(float dou) {
        if (dou == 0) {
            return "0.00";
        }
        DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(Locale.ENGLISH);
        format.applyPattern("0.00");
        return format.format(new BigDecimal(String.valueOf(dou)));
    }

    public static String round(Double dou) {
        if (null == dou || dou == 0) {
            return "0.00";
        }
        DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(Locale.ENGLISH);
        format.applyPattern("0.00");
        return format.format(new BigDecimal(String.valueOf(dou)));
    }

    /**
     * 越南千分位处理
     *
     * @param dou data
     */
    public static String roundVN(Double dou) {
        if (null == dou || dou == 0) {
            return "0.000";
        }
        DecimalFormat format = new DecimalFormat("####,###");
        return format.format(new BigDecimal(String.valueOf(dou)));
    }

    public static BigDecimal round(BigDecimal v) {
        if (null == v) {
            return BigDecimal.ZERO.setScale(COMMONSCALE);
        }
        return v.setScale(COMMONSCALE, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 判断是否大于0
     *
     * @return
     */
    public static boolean compareZero(BigDecimal bigDecimal) {
        if (bigDecimal == null) {
            return false;
        }
        return bigDecimal.compareTo(BigDecimal.ZERO) > 0;
    }

    /**
     * 判断是否大于0,返回当前值,否则返回0
     *
     * @param v
     * @return
     */
    public static BigDecimal roundZero(BigDecimal v) {
        return compareZero(round(v)) ? round(v) : BigDecimal.ZERO.setScale(COMMONSCALE);
    }

    /**
     * 格式化越南盾金额（支持小数，每3位加一个点）
     * 规则：
     * - 整数部分：从右往左每3位加一个点（.）
     * - 小数部分：如果有有效数字就显示，去掉末尾的0；如果没有有效数字就不显示小数点
     * 示例：
     * - 3000 -> "3.000"
     * - 3000.00 -> "3.000"
     * - 3000.50 -> "3.000.5"
     * - 300000 -> "300.000"
     *
     * @param amount 金额
     * @return 格式化后的金额字符串
     */
    public static String formatVietnameseDong(double amount) {
        if (amount == 0) {
            return "0";
        }

        // 分离整数部分和小数部分
        long integerPart = (long) Math.floor(Math.abs(amount));
        double decimalPart = Math.abs(amount) - integerPart;
        boolean isNegative = amount < 0;

        // 格式化整数部分：从右往左每3位加一个点
        StringBuilder integerStr = new StringBuilder(String.valueOf(integerPart));
        int length = integerStr.length();

        // 从右往左每3位插入一个点
        for (int i = length - 3; i > 0; i -= 3) {
            integerStr.insert(i, ".");
        }

        // 如果有负号，添加到开头
        if (isNegative) {
            integerStr.insert(0, "-");
        }

        // 处理小数部分
        // 使用精度比较，避免浮点数精度问题
        if (Math.abs(decimalPart) > 0.0001) {
            // 将小数部分转换为字符串，保留足够的小数位以便去掉末尾的0
            String decimalStr = String.format(Locale.ENGLISH, "%.10f", decimalPart);
            // 去掉前导的"0."
            if (decimalStr.startsWith("0.")) {
                decimalStr = decimalStr.substring(2);
            }
            // 去掉末尾的0
            decimalStr = decimalStr.replaceAll("0+$", "");
            // 去掉末尾的点（如果只剩下点）
            if (decimalStr.endsWith(".")) {
                decimalStr = decimalStr.substring(0, decimalStr.length() - 1);
            }

            // 如果还有有效小数部分，添加到结果中
            if (decimalStr.length() > 0 && !decimalStr.equals("0") && !decimalStr.equals("0.")) {
                return integerStr.toString() + "." + decimalStr;
            }
        }

        return integerStr.toString();
    }

    /**
     * 格式化越南盾金额（支持小数，每3位加一个点）
     * Float 版本
     *
     * @param amount 金额
     * @return 格式化后的金额字符串
     */
    public static String formatVietnameseDong(float amount) {
        return formatVietnameseDong((double) amount);
    }

    /**
     * 格式化越南盾金额（支持小数，每3位加一个点）
     * Double 版本（可处理null）
     *
     * @param amount 金额
     * @return 格式化后的金额字符串
     */
    public static String formatVietnameseDong(Double amount) {
        if (amount == null) {
            return "0";
        }
        return formatVietnameseDong(amount.doubleValue());
    }

}
